package bpf

import (
	"fmt"
	"os"
	"unsafe"

	"github.com/cilium/ebpf/rlimit"
)

type Hook struct {
}

type ModuleKey struct {
	Key uint32
}
type ModuleValue struct {
	Value uint32
}

func (k *ModuleKey) String() string            { return fmt.Sprintf("key=%d", k.Key) }
func (k *ModuleKey) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
func (k *ModuleKey) NewValue() MapValue        { return &ModuleValue{} }
func (k *ModuleKey) DeepCopyMapKey() MapKey    { return &ModuleKey{k.Key} }

func (v *ModuleValue) String() string              { return fmt.Sprintf("value=%d", v.Value) }
func (v *ModuleValue) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) }
func (v *ModuleValue) DeepCopyMapValue() MapValue  { return &ModuleValue{v.Value} }

func AddMap(mapname string) *Map {
	if err := rlimit.RemoveMemlock(); err != nil {
		fmt.Errorf("Failed to configure rlimit")
		return nil
	}
	maxEntries := 16
	testMap := NewMap(mapname,
		MapTypeHash,
		&ModuleKey{},
		int(unsafe.Sizeof(ModuleKey{})),
		&ModuleValue{},
		int(unsafe.Sizeof(ModuleValue{})),
		maxEntries,
		BPF_F_NO_PREALLOC,
		0,
		ConvertKeyValue,
	).WithCache()

	testMap.OpenOrCreate()
	return testMap

}

func RemoveMap(mapname string) {
	if err := rlimit.RemoveMemlock(); err != nil {
		fmt.Errorf("Failed to configure rlimit")
		return
	}
	testMap, err := OpenMap(mapname)
	if err != nil {
		fmt.Printf("map name %s not  exists!", mapname)
	}
	testMap.Close()
	path, _ := testMap.Path()
	os.Remove(path)

}

func UpdateMap(mapname string, key uint32, value uint32) error {
	if err := rlimit.RemoveMemlock(); err != nil {
		fmt.Errorf("Failed to configure rlimit %v", err)
		return err
	}
	testMap, err := OpenMap(mapname)
	if err != nil {
		fmt.Printf("map name %s not  exists!", mapname)
		return err
	}
	updatkey := &ModuleKey{Key: key}
	updatevalue := &ModuleValue{Value: value}
	err = testMap.Update(updatkey, updatevalue)
	return err
}

func DelMapRow(mapname string, key uint32) error {
	if err := rlimit.RemoveMemlock(); err != nil {
		fmt.Errorf("Failed to configure rlimit %v", err)
		return err
	}
	testMap, err := OpenMap(mapname)
	if err != nil {
		fmt.Printf("map name %s not  exists!", mapname)
		return err
	}
	updatkey := &ModuleKey{Key: key}
	err = testMap.Delete(updatkey)
	return err
}
func ListMap(mapname string) map[ModuleKey]MapValue {
	if err := rlimit.RemoveMemlock(); err != nil {
		fmt.Errorf("Failed to configure rlimit %v", err)
		return nil
	}
	testMap, err := OpenMap(mapname)
	if err != nil {
		fmt.Printf("map name %s not  exists!", mapname)
		return nil
	}
	//遍历maps
	mkeys := make(map[ModuleKey]MapValue)
	var nextKey = ModuleKey{}
	var key = ModuleKey{}
	for {
		err := GetNextKey(testMap.GetFd(), unsafe.Pointer(&key), unsafe.Pointer(&nextKey))
		if err != nil {
			break
		}
		key = nextKey
		value, _ := testMap.Lookup(&nextKey)
		mkeys[key] = value
	}

	return mkeys
}
